In distributed version control systems, such as Git or Mercurial, a source code repository may exist on multiple client or server devices. Each device may contain a different form of the code repository, containing different versions of source code files than other client repositories. One repository may be a subset, a superset, or a mixture of both a subset and a superset, of another repository depending on the revisions that were made in the specific repository.
Repositories may diverge in many ways. New revisions may be added to one repository and not others, conflicting revisions may be added to separate repositories, and/or files may be deleted from repositories. The revisions in a repository can be viewed as a graph containing nodes (each node reflecting an entire file tree), linked by parent relationships, as well as a set of named references that each point to some node in the graph.
At some points in time, it may be necessary to synchronize the repositories. In some cases, synchronization may be simple. For example, a repository A may contain several revisions and a second repository B may contain no revisions. To synchronize these repositories, the revisions in repository A may be copied to repository B. After the synchronization operation, repositories A and B are identical.
However, it is often difficult to synchronize changes among repositories because there may be complicated and conflicting differences between the revisions in repository A and repository B. In order to handle these differences, a merging strategy may be defined as to how to synchronize the repositories. For example, a clobber strategy may be used that resolves any conflicts between A and B in favor of A. Another strategy may be to ask the user, requiring human intervention to resolve any conflicts interactively. A third strategy may be the “timid strategy” which aborts any synchronization operation that might cause a conflict.
One strategy that works without human-operator intervention is to perform only one-way synchronization. If all intentional user modifications happen in repository A, then it is trivial to set up repository B as a one-way mirror of repository A using repeated invocations of the clobber strategy discussed above. However, there are times when it is desirable to add a new revision to repository B and then push the revision to repository A, while retaining the ability to perform future one-way synchronizations from repository A to repository B without observing conflicts. When synchronizing repository A and B if both repositories have changed, there may be several potential conflicts that arise. One user may add a new revision, revision R, to repository B, necessitating updating a reference Ref to point to the revision R, and then synchronizing the revision R to repository A. However, during this process, another user may add revision R′ to repository A and update reference Ref to point to R′ before the synchronization from repository B to repository A can occur. Therefore, when synchronization occurs there may be a conflict between the references that requires human-operator intervention.